import 'dart:async';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter_yn_goods/config/app_config.dart';
import 'package:flutter_yn_goods/utils/http/http_core.dart';
import 'package:flutter_yn_goods/utils/http/http_export.dart';
import 'package:flutter_yn_goods/utils/http/http_handler.dart';
import 'package:flutter_yn_goods/utils/http/ui/http_loading.dart';
import 'package:flutter_yn_goods/utils/http/ui/http_toast.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;

import 'http_log_interceptor.dart';
import 'request_interceptor.dart';
import 'response_interceptor.dart';

class HttpManager {
  static final HttpManager _instance = HttpManager._();

  factory HttpManager() => _instance;

  late Dio _dio;

  Function(int? code)? errorCodeListener;

  HttpManager._() {
    BaseOptions baseOptions = BaseOptions(
      baseUrl: AppConfig.baseUrl,
      connectTimeout: const Duration(milliseconds: 10 * 1000),
      contentType: 'application/json;Charset=UTF-8',
      responseType: ResponseType.json,
    );

    _dio = Dio(baseOptions);

    _dio.interceptors.add(RequestInterceptor());
    _dio.interceptors.add(ResponseInterceptor());

    /// 非正式环境拦截日志打印
    if (!const bool.fromEnvironment("dart.vm.product")) {
      _dio.interceptors.add(HttpLogInterceptor());
    }
  }

  Future<HttpResponse> get<T>(
    api, {
    params,
    T Function(Map<String, dynamic>)? fromJson,
    void Function(HttpResponse response)? handleError,
    HttpUIType uiType = HttpUIType.toast,
  }) async {
    return _showUI(
            _dio.getRequest(api, queryParameters: params, data: params), uiType)
        .handler<T>(fromJson, handleError, errorCodeListener);
  }

  Future<HttpResponse> post<T>(
    api, {
    params,
    T Function(Map<String, dynamic>)? fromJson,
    void Function(HttpResponse response)? handleError,
    HttpUIType uiType = HttpUIType.toast,
    CancelToken? cancelToken,
  }) async {
    return _showUI(
            _dio.postRequest(api, data: params, cancelToken: cancelToken),
            uiType)
        .handler<T>(fromJson, handleError, errorCodeListener);
  }

  Future<HttpResponse> put<T>(
    api, {
    params,
    T Function(Map<String, dynamic>)? fromJson,
    void Function(HttpResponse response)? handleError,
    HttpUIType uiType = HttpUIType.none,
  }) async {
    return _showUI(_dio.putRequest(api, data: params), uiType)
        .handler(fromJson, handleError, errorCodeListener);
  }

  Future<HttpResponse> delete<T>(
    api, {
    params,
    T Function(Map<String, dynamic>)? fromJson,
    void Function(HttpResponse response)? handleError,
    HttpUIType uiType = HttpUIType.none,
  }) async {
    return _showUI(_dio.deleteRequest(api, data: params), uiType)
        .handler(fromJson, handleError, errorCodeListener);
  }

  Future<HttpResponse> _showUI(
      Future<HttpResponse> future, HttpUIType uiType) async {
    switch (uiType) {
      case HttpUIType.loading:
        future = future.loading();
        break;
      case HttpUIType.toast:
        future = future.toast();
        break;
      case HttpUIType.loadingAndToast:
        future = future.loading().toast();
        break;
      case HttpUIType.none:
        break;
    }
    return future;
  }

//  图片格式限制jpg或jpeg,文件名必须带后缀
  Future<HttpResponse> upload<T>({
    required List<int> fileData,
    String? requestId,
    ProgressCallback? onSendProgress,
    CancelToken? cancelToken,
    required String fileName,
    T Function(Map<String, dynamic>)? fromJson,
    HttpUIType uiType = HttpUIType.loadingAndToast,
    bool enableCompression = true, // 是否开启压缩
  }) async {
    List<int> processedData = fileData;

    // 判断是否需要压缩（大于1MB的图片才压缩）
    if (enableCompression && fileData.length > 1024 * 1024) {
      processedData = await _compressImage(fileData, fileName);
    }

    var file = MultipartFile.fromBytes(processedData,
        filename: fileName.toLowerCase());
    FormData formData =
        FormData.fromMap({'file': file, 'request_id': requestId});
    return await _showUI(
        _dio
            .postRequest(API.upload,
                data: formData,
                options: Options(
                  // extra: {"isUploadFile": true},
                  sendTimeout: const Duration(seconds: 60),
                  receiveTimeout: const Duration(seconds: 60),
                ),
                onSendProgress: onSendProgress,
                cancelToken: cancelToken)
            .handler(fromJson, null, errorCodeListener),
        uiType);
  }

  // 压缩图片功能
  Future<List<int>> _compressImage(List<int> imageData, String fileName) async {
    try {
      // 压缩图片到5MB以内
      final int maxSize = 5 * 1024 * 1024; // 5MB

      // 如果已经小于5MB，直接返回原图
      if (imageData.length <= maxSize) {
        return imageData;
      }

      // 创建临时文件
      final tempDir = await getTemporaryDirectory();
      final tempPath = path.join(tempDir.path,
          'temp_${DateTime.now().millisecondsSinceEpoch}$fileName');
      final compressedPath = path.join(tempDir.path,
          'compressed_${DateTime.now().millisecondsSinceEpoch}$fileName');

      // 写入原始数据
      final file = File(tempPath);
      await file.writeAsBytes(imageData);

      // 获取文件扩展名
      final ext = path.extension(fileName).toLowerCase();

      // 根据图片类型选择压缩方法
      List<int> compressedData;

      // 计算压缩质量，根据文件大小动态调整
      int quality = 80; // 默认压缩质量
      if (imageData.length > 10 * 1024 * 1024) {
        // 大于10MB
        quality = 60;
      } else if (imageData.length > 5 * 1024 * 1024) {
        // 大于5MB
        quality = 70;
      }

      if (ext == '.jpg' || ext == '.jpeg') {
        compressedData = await FlutterImageCompress.compressWithFile(
              file.path,
              minWidth: 1080,
              minHeight: 1080,
              quality: quality,
            ) ??
            imageData;
      } else if (ext == '.png') {
        compressedData = await FlutterImageCompress.compressWithFile(
              file.path,
              minWidth: 1080,
              minHeight: 1080,
              quality: quality,
              format: CompressFormat.png,
            ) ??
            imageData;
      } else {
        // 不支持的格式，返回原图
        return imageData;
      }

      // 如果压缩后仍然超过5MB，继续递减质量压缩
      if (compressedData.length > maxSize) {
        final compressedFile = File(compressedPath);
        await compressedFile.writeAsBytes(compressedData);

        int newQuality = quality - 10;
        while (newQuality >= 30 && compressedData.length > maxSize) {
          compressedData = await FlutterImageCompress.compressWithFile(
                compressedFile.path,
                minWidth: 1080,
                minHeight: 1080,
                quality: newQuality,
                format:
                    ext == '.png' ? CompressFormat.png : CompressFormat.jpeg,
              ) ??
              compressedData;

          newQuality -= 10;
        }
      }

      // 清理临时文件
      await file.delete();

      return compressedData;
    } catch (e) {
      print('图片压缩失败: $e');
      // 压缩失败时返回原图
      return imageData;
    }
  }

  Future<HttpResponse> download({
    required String url,
    required String savePath,
    Map<String, dynamic>? queryParameters,
    ProgressCallback? onReceiveCallback,
    CancelToken? cancelToken,
  }) async {
    late HttpResponse httpResponse;
    var isComplete = false;
    await _dio.download(url, savePath,
        cancelToken: cancelToken,
        options: Options(
          sendTimeout: const Duration(seconds: 60),
          receiveTimeout: const Duration(seconds: 300),
          extra: {"isUploadFile": true},
        ), onReceiveProgress: (count, total) {
      onReceiveCallback?.call(count, total);
      isComplete = count == total;
    }).then((response) {
      httpResponse =
          HttpResponse(status: HttpCode.code200, message: 'success', data: {});
    }).catchError((error) async {
      httpResponse = await _handleDioException(error);
    }).whenComplete(() async {
      if (httpResponse.isSuccess) {
        httpResponse = HttpResponse(
            status: HttpCode.code200,
            message: isComplete ? "success" : '下载未完成',
            data: isComplete ? savePath : null);
      }
    });
    return httpResponse;
  }

  Future<HttpResponse> _handleDioException(error) async {
    DioException exception = error;
    DioExceptionType type = exception.type;
    // if (type == DioExceptionType.connectionError && isNoNetWork == false) {
    //   await HttpConnectionCheck.checkNetWork(listen: false);
    // }
    // if (type == DioExceptionType.unknown) {
    //   await HttpConnectionCheck.checkNetWork(listen: false);
    //   if (isNoNetWork) {
    //     type = DioExceptionType.connectionError;
    //   }
    // }
    HttpResponse response =
        HttpResponse(type: type, message: exception.message);
    response = HttpHandleError.adjust(response, exception: exception);
    return response;
  }
}
